/**
 * Copyright (C) 2017 - 2020 https://github.com/joewee
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.bifrost.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.bifrost.common.model.ResultModel;
import com.bifrost.common.util.HttpRequestUtils;
import com.bifrost.constant.*;
import com.bifrost.constant.OrderType;
import com.bifrost.entity.*;
import com.bifrost.exception.*;
import com.bifrost.model.*;
import com.bifrost.repository.*;
import com.bifrost.service.*;
import com.bifrost.service.ProductService;
import com.bifrost.uid.UidGenerator;
import com.bifrost.util.DateUtils;
import com.bifrost.util.LocalDateUtils;
import com.bifrost.util.NumberUtils;
import com.bifrost.util.PurchaseOrderCodeUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.exception.LockAcquisitionException;
import org.jetbrains.annotations.Nullable;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author joewee
 * @version 1.0.0
 * @Date 2017/11/12 22:49
 */
@Service("orderService")
public class OrderServiceImpl implements OrderService {
    private static final Logger LOGGER = LoggerFactory.getLogger(OrderServiceImpl.class);

    @Autowired
    ProductSkuService productSkuService;
    @Autowired
    ServicePriceRepository servicePriceRepository;
    @Autowired
    StoreService storeService;
    @Autowired
    OrderRepository orderRepository;
    @Autowired
    PricingService pricingService;
    @Autowired
    CustomerService customerService;
    @Autowired
    CouponService couponService;
    @Autowired
    PaymentService paymentService;
    @Autowired
    CountryAreaService areaService;
    @Autowired
    ProductSkuRepository productSkuRepository;
    @Autowired
    CountryAreaService countryAreaService;
    @Autowired
    UidGenerator defaultUidGenerator;
    @Autowired
    ShippingService shippingService;
    @Autowired
    SkuAssociationRepository skuAssociationRepository;
    @Autowired
    InventoryService inventoryService;
    @Autowired
    OrderStatusHistoryService statusHistoryService;
    @Autowired
    RefundRequestService refundRequestService;
    @Autowired
    PromotionService promotionService;
    @Autowired
    OrderReturnRepository orderReturnRepository;
    @Autowired
    OrderStatusHistoryService orderStatusHistoryService;
    @Autowired
    ProductService productService;
    @Autowired
    OrderAttributeRepository orderAttributeRepository;

    @Autowired
    MemberService memberService;
    @Autowired
    AdminUserService userService;
    @Autowired
    RedissonClient redisson;
    @Autowired
    PromotionConstraintRepository promotionConstraintRepository;
    @Autowired
    BonusPointsService bonusPointsService;
    @Autowired
    CouponDetailRepository couponDetailRepository;
    @Autowired
    CouponRepository couponRepository;
    @Autowired
    OrderItemRepository orderItemRepository;
    @Autowired
    CouponHistroyRepository couponHistroyRepository;

    @Value("${cbest.member.send.sale:#{null}}")
    private String url;
    @Value("${cbest.accessKey}")
    private  String accessKey;

    @Value("${pricing.retry.count.for.lock.failure}")
    protected int pricingRetryCountForLockFailure = 3;

    @Value("${pricing.retry.wait.interval.for.lock.failure}")
    protected long pricingRetryWaitIntervalForLockFailure = 500L;

    @Value("${running.mode:#{null}}")
    private String runningMode;

    @Override
    public boolean isValidRequest(OrderRequest request) {
        List<ItemModel> items = request.getProducts();
        if (items == null || items.isEmpty()) {
            return false;
        }
        String orderType = request.getOrderType();
        if (!isValidOrderType(orderType)) {
            return false;
        }
        for (ItemModel itemModel : items) {
            if (itemModel.getSkuId() == null || itemModel.getQuantity() <= 0) {
                return false;
            }
            //普通订单行项目不能有团购、积分兑换、秒杀促销
            if (OrderType.GENERAL.equalsIgnoreCase(orderType) && itemModel.isPromotionApplied()) {
                return false;
            }
        }
        return true;
    }

    /**
     * 根据request 对象生成order
     *
     * @param request
     * @return
     */
    @Override
    public Order newOrder(OrderRequest request, Customer customer) {
        Order order = new Order();
        order.setCustomer(customer);
        order.setOrderType(request.getOrderType());
        order.setServiceShop(request.getServiceShop());
        order.setNeedService(request.isNeedService());
        order.setOrderItems(new ArrayList<OrderItem>());
        order.setShippingType(request.getShippingType());
        Long district = request.getDistrict();
        Long state = request.getState();
        Long city = request.getCity();
        if (district != null) {
            order.setDeliveryDistrict(countryAreaService.getArea(district));
        }
        if (city != null) {
            order.setDeliveryCity(countryAreaService.getArea(city));
        }
        if (state != null) {
            order.setDeliveryState(countryAreaService.getArea(state));
        }
        if (request.getServiceShop() != null) {
            order.setServiceShop(request.getServiceShop());
        }
        request.getProducts().forEach(itemModel -> {
            OrderItem item = new OrderItem();
            item.setSkuId(itemModel.getSkuId());
            item.setSkuQuantity(itemModel.getQuantity());
            item.setIsPromoApplied(itemModel.isPromotionApplied());
            item.setAppliedPromoId(itemModel.getAppliedPromotionId());
            order.getOrderItems().add(item);
        });
        //生成uid
        //order.setOrderNumber(generateOrderNumber(customer.getCustomerId()));
        return order;
    }

    @Override
    public Order newOrder(OrderModel request, Customer customer) {
        Order order = new Order();
        order.setCustomer(customer);
        order.setNeedService(request.isNeedService());
        order.setShippingType(request.getShippingType());
        String orderType = request.getOrderType();
        order.setOrderType(orderType);
        order.setIsBonusPointsUsed(request.getIsBonusPointsUsed());
        order.setBonusPointsUsed(request.getBonusPointsUsed());
        if (Boolean.TRUE.equals(request.isNeedInvoice())) {
            order.setNeedInvoice(Boolean.TRUE);
            order.setInvoiceType(request.getInvoiceType());
            order.setInvoiceTitle(request.getInvoiceTitle());
            order.setTaxNumber(request.getTaxNumber());
        }
        if (Boolean.TRUE.equals(request.isNeedService())) {
            order.setNeedService(Boolean.TRUE);
            Long shopId = request.getServiceShop();
            order.setServiceShop(shopId);
            MerchantStore shop = storeService.getMerchantStore(shopId);
            order.setDeliveryState(shop.getStoreState());
            order.setDeliveryCity(shop.getStoreCity());
            order.setDeliveryDistrict(shop.getStoreState());
            order.setDeliveryStreet(shop.getStoreStreet());
            order.setPreorderTime(request.getPreorderTime());
            order.setShippingType(ShippingType.SELF_DELIVERY);
        } else {
            order.setDeliveryState(areaService.getArea(request.getState()));
            order.setDeliveryCity(areaService.getArea(request.getCity()));
            order.setDeliveryDistrict(areaService.getArea(request.getDistrict()));
            order.setDeliveryStreet(request.getStreet());
            order.setPreorderTime(request.getPreorderTime());
            if (StringUtils.isEmpty(request.getShippingType())) {
                order.setShippingType(ShippingType.DELIVERY);
            } else {
                order.setShippingType(request.getShippingType());
            }
        }
        order.setDeliveryLastName(request.getLastname());
        order.setDeliveryPhoneSecondary(request.getPrimaryPhone());
        order.setDeliveryTelephonePrimary(request.getPrimaryPhone());
        order.setPayment(paymentService.getPayment(request.getPayment()));
        order.setCustomerMessage(request.getMsg());
        order.setOrderItems(new ArrayList<>());
        request.getItems().forEach(itemModel -> {
            OrderItem item = new OrderItem();
            item.setSkuId(itemModel.getSkuId());
            item.setSkuQuantity(itemModel.getQuantity());
            item.setIsPromoApplied(itemModel.isPromotionApplied());
            item.setAppliedPromoId(itemModel.getAppliedPromotionId());
            order.getOrderItems().add(item);
        });
        Set<Long> coupons = request.getCoupons();
        if (coupons != null && !coupons.isEmpty()) {
            List<CouponDetail> details = couponService.getCustomerCouponByCode(customer, coupons);
            if (details != null && !details.isEmpty()) {
                if (order.getOrderCoupons() == null) {
                    order.setOrderCoupons(new ArrayList<>());
                }
                details.forEach(coupondetail -> {
                    OrderCoupon orderCoupon = new OrderCoupon();
                    orderCoupon.setCouponDetail(coupondetail);
                    orderCoupon.setOrder(order);
                    orderCoupon.setOrderNumber(order.getOrderNumber());
                    //orderCoupon.setTradeNumber(String.format("%d",defaultUidGenerator.getUID()));
                    orderCoupon.setCouponCode(coupondetail.getCouponCode());
                    orderCoupon.setCouponPrice(coupondetail.getDiscountAmount());
                    orderCoupon.setCouponId(coupondetail.getCoupon().getCouponId());
                    order.getOrderCoupons().add(orderCoupon);
                });
            }
        }
        return order;
    }

    /**
     * @param order
     * @return
     * @throws UnsupportedShippingTypeException
     * @throws PromotionException
     */
    @Override
    public Order getConfirmOrderData(Order order) throws UnsupportedShippingTypeException, PromotionException, ProductUnavaliableException {

        List<OrderItem> items = order.getOrderItems();
        Customer customer = order.getCustomer();
        Long serviceShop = order.getServiceShop();
        if (items == null || items.isEmpty()) {
            throw new RuntimeException("订单项目为空");
        }
        List<String> shippingTypes = new ArrayList<>();
        List<Integer> preorderDays = new ArrayList<>(items.size());
        for (OrderItem item : items) {
            item.setOrder(order);
            Long sku = item.getSkuId();
            ProductSku productSku = productSkuService.getSkuById(sku);
            if (productSku==null||!productSkuService.isAvailable(productSku)) {
                throw new ProductUnavaliableException("商品不可用");
            }
            Product product = productSku.getProduct();
            Long promotionId = item.getAppliedPromoId();
            String shippingType = productSku.getFulfillmentType();
            if (shippingType != null && !shippingTypes.contains(shippingType)) {
                shippingTypes.add(shippingType);
            }
            if (item.isPromoApplied() && promotionId != null) {
                //含有促销
                item.setSkuName(productSku.getSkuName());
                item.setSkuCost(productSku.getSkuCost());
                item.setSkuUPC(productSku.getSkuUpc());
                item.setExternalId(productSku.getExternalId());
                item.setRetailPrice(productSku.getRetailPrice());
                item.setOrderItemType(productSku.getItemType());
                item.setCategoryId(product.getProductCategory().getCategoryId());
                item.setProductId(product.getProductId());
                item.setSkuPrice(productSku.getSalePrice());
                //获取促销活动并重新设置促销价格
                Promotion promotion = promotionService.find(promotionId);
                String promotionType = promotion.getType();
                if (!PromotionType.GROUPON.equalsIgnoreCase(promotionType) && !PromotionType.SECKILL.equalsIgnoreCase(promotionType)) {
                    throw new PromotionException(String.format("无效的促销活动:%d-%s", promotion.getId(), promotion.getType()));
                }
                if (promotion != null && !promotion.isArchived()) {
                    if (!promotion.isActive()) {
                        throw new PromotionException("活动还未开始或已结束");
                    }
                    PromotionSku promotionSku = promotionService.findByPromotionAndSku(promotion, productSku);
                    Integer availabe = promotionSku.getInventoryAvailable();
                    if(availabe==null||availabe<=0){
                        throw new PromotionException("啊喔~商品已经售罄了！");
                    }
                    if(Boolean.TRUE.equals(promotionSku.getHasLimit())){
                        if(item.getSkuQuantity().compareTo(promotionSku.getLimitQuantity()) > 0)
                            throw new PromotionException(String.format("商品%d-%s超过购买限制:%d", productSku.getSkuId(), productSku.getSkuName(), promotionSku.getLimitQuantity()));
                        PromotionConstraint promotionConstraint =
                                promotionConstraintRepository.findByCustomerAndPromotionAndProductId(customer, promotion, product.getProductId());
                        if(null != promotionConstraint){
                            Integer quantityFresh = promotionConstraint.getQuantity() + item.getSkuQuantity();
                            if(quantityFresh.compareTo(promotionSku.getLimitQuantity()) > 0){
                                throw new PromotionException(String.format("商品%d-%s超过购买限制:%d", productSku.getSkuId(), productSku.getSkuName(), promotionSku.getLimitQuantity()));
                            }
                        }
                    }
                    if (promotionSku != null) {
                        item.setSkuPrice(promotionSku.getPromotionPrice());
                    } else {
                        throw new PromotionException("该商品不参加活动");
                        //item.setSkuPrice(productSku.getSalePrice());
                    }
                }else{
                    throw new PromotionException("活动不存在或已失效");
                }
            } else {
                //需要预约
                if (Boolean.TRUE.equals(productSku.getCanPreorder())) {
                    Integer days = productSku.getPreorderDays();
                    if (days != null && days.compareTo(1) >= 0) {
                        preorderDays.add(days);
                    } else {
                        preorderDays.add(1);
                    }
                } else {
                    preorderDays.add(1);
                }
                productSkuService.pricingBundleProduct(productSku);
                //检查商品是否可用
                item.setSkuName(productSku.getSkuName());
                item.setSkuCost(productSku.getSkuCost());
                item.setSkuUPC(productSku.getSkuUpc());
                item.setExternalId(productSku.getExternalId());
                item.setSkuPrice(productSku.getSalePrice());
                item.setRetailPrice(productSku.getRetailPrice());
                item.setOrderItemType(productSku.getItemType());
                item.setCategoryId(productSku.getCategory().getCategoryId());
                item.setProductId(productSku.getProduct().getProductId());
                if (Boolean.TRUE.equals(order.isNeedService())) {
                    List<com.bifrost.entity.ProductService> serviceAssociations = productSkuService.getAssociationsOfService(productSku);
                    if (serviceAssociations != null && !serviceAssociations.isEmpty()) {
                        item.setHasService(Boolean.TRUE);
                        //未选择安装门店
                        if (serviceShop == null) {
                            serviceAssociations.forEach(productService -> {
                                if (item.getOrderItemServices() == null) {
                                    item.setOrderItemServices(new ArrayList<OrderItemService>());
                                }
                                OrderItemService itemService = new OrderItemService();
                                itemService.setOrderItem(item);
                                itemService.setProductService(productService);
                                itemService.setServiceName(productService.getServiceName());
                                itemService.setServicePrice(productService.getServicePrice());
                                item.getOrderItemServices().add(itemService);
                            });
                        } else {
                            if (item.getOrderItemServices() == null) {
                                item.setOrderItemServices(new ArrayList<OrderItemService>());
                            }
                            order.setServiceShop(serviceShop);
                            MerchantStore store = storeService.getMerchantStore(serviceShop);
                            List<ServicePrice> servicePrices = servicePriceRepository.findAllByProductServiceInAndMerchantStore(serviceAssociations, store);
                            //未设置店铺指定服务价格则取默认值
                            if (servicePrices == null || servicePrices.isEmpty()) {
                                serviceAssociations.forEach(productService -> {
                                    OrderItemService itemService = new OrderItemService();
                                    itemService.setOrderItem(item);
                                    itemService.setProductService(productService);
                                    itemService.setServiceName(productService.getServiceName());
                                    itemService.setServicePrice(productService.getServicePrice());
                                    item.getOrderItemServices().add(itemService);
                                });
                            } else {
                                servicePrices.forEach(servicePrice -> {
                                    OrderItemService itemService = new OrderItemService();
                                    com.bifrost.entity.ProductService productService = servicePrice.getProductService();
                                    itemService.setOrderItem(item);
                                    itemService.setProductService(productService);
                                    itemService.setServiceName(productService.getServiceName());
                                    itemService.setServicePrice(servicePrice.getServicePrice());
                                    itemService.setMerchantStore(store);
                                    itemService.setMerchantStoreName(store.getStoreName());
                                    item.getOrderItemServices().add(itemService);
                                });
                            }
                        }
                    } else {
                        item.setHasService(Boolean.FALSE);
                    }

                }
                List<ProductSku> giftSkus = productSkuService.getAssociationsOfGift(productSku);
                if (giftSkus != null && !giftSkus.isEmpty()) {
                    item.setHasGift(Boolean.TRUE);
                    giftSkus.forEach(giftSku -> {
                        if (productSkuService.isAvailable(giftSku)) {
                            if (item.getGiftwrapOrderItems() == null) {
                                item.setGiftwrapOrderItems(new ArrayList<>());
                            }
                            /**
                             * 礼品商品不为绑定商品
                             * */
                            GiftwrapOrderItem giftwrapOrderItem = new GiftwrapOrderItem();
                            giftwrapOrderItem.setSkuCost(giftSku.getSkuCost());
                            giftwrapOrderItem.setCategoryId(giftSku.getCategory().getCategoryId());
                            giftwrapOrderItem.setExternalId(giftSku.getExternalId());
                            giftwrapOrderItem.setProductId(giftSku.getProduct().getProductId());
                            giftwrapOrderItem.setSkuPrice(giftSku.getSalePrice());
                            giftwrapOrderItem.setSkuUPC(giftSku.getSkuUpc());
                            if (!ProductSkuType.BUNDLE.equalsIgnoreCase(giftSku.getItemType())) {
                                giftwrapOrderItem.setOrderItem(item);
                                giftwrapOrderItem.setQuantity(1);
                                giftwrapOrderItem.setProductSku(giftSku);
                                item.getGiftwrapOrderItems().add(giftwrapOrderItem);
                            } else {
                                //TODO 当礼品为绑定商品时需要获取绑定商品明细
                                giftwrapOrderItem.setOrderItem(item);
                                giftwrapOrderItem.setProductSku(giftSku);
                                giftwrapOrderItem.setQuantity(1);
                                item.getGiftwrapOrderItems().add(giftwrapOrderItem);
                            }
                            //ItemModel item = TransformUtils.transformToItemModel(giftSku);
                            //item.setImageUrl(productSkuService.getSkuDefaultMedia(giftSku).getUrl());
                            //orderModel.getGifts().add(item);
                        }
                    });
                }
            }


        }
        String shippingOptions = shippingService.findBestShippingType(shippingTypes);
        order.setShippingOptions(shippingOptions);
        if(ShippingType.BOTH.equalsIgnoreCase(shippingOptions)){
            if (StringUtils.isBlank(order.getShippingType())) {
                order.setShippingType(ShippingType.DELIVERY);
            }
        }else{
            order.setShippingType(shippingOptions);
        }
        /*if(StringUtils.isBlank(order.getShippingType())){
            String shippingType = shippingService.findBestShippingType(shippingTypes);
            order.setShippingType(shippingType);
        }*/
        /*Date orderDate = order.getPreorderTime();
        Date minDate = calculatePreorderDate(preorderDays);
        if (orderDate == null || orderDate.before(minDate)) {
            order.setPreorderTime(minDate);
        }*/

        return order;
    }

    /**
     * 获取所有订单
     *
     * @param page            page
     * @param pageSize        pageSize
     * @param customer        customer
     * @param store           store
     * @param status          status
     * @param isGetNotComment
     * @return List
     */
    @Override
    public List<OrderResult> getOrders(Integer page, Integer pageSize, Customer customer, MerchantStore store, String status, boolean isGetNotComment) {
        List<OrderResult> orders = new ArrayList<>();
        Pageable pageable = new PageRequest(page - 1, pageSize, new Sort(Sort.Direction.DESC, "orderNumber"));
        Specification<Order> query = new Specification<Order>() {
            @Override
            public Predicate toPredicate(Root<Order> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();
                predicates.add(cb.equal(root.get("customer"), customer));
                if (store != null) {
                    predicates.add(cb.equal(root.get("merchantStore"), store));
                }
                if (isGetNotComment) {
                    predicates.add(cb.equal(root.get("orderStatus"), OrderStatus.FINISHED));
                    predicates.add(cb.equal(root.get("commentStatus"), CommentStatus.NOT_COMMENT));
                } else {
                    if (StringUtils.isNotEmpty(status)) {
                        //待收货：PAID, CONFIRMED, SHIPPED
                        if(OrderStatus.SHIPPED.equalsIgnoreCase(status)){
                            CriteriaBuilder.In<String> in = cb.in(root.get("orderStatus"));
                            in.value(OrderStatus.PAID);
                            in.value(OrderStatus.CONFIRMED);
                            in.value(OrderStatus.SHIPPED);
                            predicates.add(in);
                        }else {
                            predicates.add(cb.equal(root.get("orderStatus"), status));
                        }
                    }
                }
                Predicate[] p = new Predicate[predicates.size()];
                return cb.and(predicates.toArray(p));
            }
        };
        Page<Order> data = orderRepository.findAll(query, pageable);
        if (!data.hasContent()) {
            return null;
        }
        List<Order> list = data.getContent();
        if (list == null || list.isEmpty()) {
            return null;
        }
        for (Order order : list) {
            OrderResult orderResult = orderOverview(order);
            if (orderResult != null){
                orders.add(orderResult);
            }
        }
        return orders;
    }

    /**
     * 创建订单编号
     *
     * @return
     */
    @Override
    public String generateOrderNumber(Long customerId) {
        return null;
    }

    /**
     * 是否有效的订单(该方法适用于订单提交时的校验)<br>
     * <p>
     * 验证是否有有效的行项目<br>
     * 验证是否有有效的订单类型<br>
     * 保养订单则设置必要信息<br>
     * 验证车辆信息有效性<br>
     * 验证支付方式有效性<br>
     * 验证收货地址<br>
     * 验证行项目商品数量有效性<br>
     * </p>
     *
     * @param order
     * @return
     */
    @Override
    public boolean isValidOrder(OrderModel order) {
        List<ItemModel> items = order.getItems();
        if (items == null || items.isEmpty()) {
            return false;
        }
        String orderType = order.getOrderType();
        if (!isValidOrderType(orderType)) {
            return false;
        }
        for (ItemModel itemModel : items) {
            if (itemModel.getSkuId() == null || itemModel.getQuantity() <= 0) {
                return false;
            }
            //普通订单行项目不能有团购、积分兑换、秒杀促销
            if (OrderType.GENERAL.equalsIgnoreCase(orderType) && itemModel.isPromotionApplied()) {
                return false;
            }
        }
        Long pay = order.getPayment();
        if (paymentService.getPayment(pay) == null) {
            return false;
        }
        if (ShippingType.BOTH.equalsIgnoreCase(order.getShippingType())){
            return false;
        }else if (ShippingType.DELIVERY.equalsIgnoreCase(order.getShippingType()))
        {
            if (order.getCity() == null || order.getState() == null || order.getDistrict() == null || StringUtils.isEmpty(order.getStreet())) {
                return false;
            }
        }else if(ShippingType.SELF_DELIVERY.equalsIgnoreCase(order.getShippingType())){

        }else{
            return false;
        }
        return true;
    }

    /**
     * 是否有效的订单类型
     *
     * @param orderType
     * @return
     */
    @Override
    public boolean isValidOrderType(String orderType) {
        if (StringUtils.isNotEmpty(orderType)) {
            return orderType.equals(OrderType.GENERAL) ||
                    orderType.equals(OrderType.EXCHANGE) || orderType.equals(OrderType.GROUPON)
                    || orderType.equals(OrderType.SECKILL);
        }
        return false;
    }

    /**
     * 保存订单
     *
     * @param order 订单
     * @return 订单
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public Order save(Order order) {
        return orderRepository.save(order);
    }

    /**
     * 保存订单
     *
     * @param order      订单
     * @param priceOrder 是否重新计价
     * @return 订单
     */
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Order save(Order order, boolean priceOrder) throws PricingException {

        order = persist(order);
        if (priceOrder) {
            int retryCount = 0;
            boolean isValid = false;
            while (!isValid) {
                try {
                    order = pricingService.executePricing(order);
                    isValid = true;
                } catch (Exception ex) {
                    boolean isValidCause = false;
                    Throwable cause = ex;
                    while (!isValidCause) {
                        if (cause.getClass().equals(LockAcquisitionException.class)) {
                            isValidCause = true;
                        }
                        cause = cause.getCause();
                        if (cause == null) {
                            break;
                        }
                    }
                    if (isValidCause) {
                        if (LOGGER.isInfoEnabled()) {
                            LOGGER.info("Problem acquiring lock during pricing call - attempting to price again.");
                        }
                        isValid = false;
                        if (retryCount >= pricingRetryCountForLockFailure) {
                            if (LOGGER.isInfoEnabled()) {
                                LOGGER.info("Problem acquiring lock during pricing call. Retry limit exceeded at (" + retryCount + "). Throwing exception.");
                            }
                            if (ex instanceof PricingException) {
                                throw (PricingException) ex;
                            } else {
                                throw new PricingException(ex);
                            }
                        } else {
                            order = findOrderById(order.getOrderId());
                            retryCount++;
                        }
                        try {
                            Thread.sleep(pricingRetryWaitIntervalForLockFailure);
                        } catch (Throwable e) {
                            //do nothing
                        }
                    } else {
                        if (ex instanceof PricingException) {
                            throw (PricingException) ex;
                        } else {
                            throw new PricingException(ex);
                        }
                    }
                }
            }
            return null;
        }
        return order;
    }

    /**
     * 转换成前端可显示的model
     *
     * @param order 订单
     * @return OrderModel
     */
    @Override
    public OrderModel convertToOrderModel(Order order) {
        OrderModel orderModel = new OrderModel();
        MerchantStore store = order.getMerchantStore();
        orderModel.setMerchantStore(store == null ? null : store.getMerchantId());
        orderModel.setCustomerId(order.getCustomer() == null ? null : order.getCustomer().getCustomerId());
        orderModel.setOrderNumber(order.getOrderNumber());
        orderModel.setServiceShop(order.getServiceShop());
        orderModel.setShippingType(order.getShippingType());
        orderModel.setOrderType(order.getOrderType());
        orderModel.setPreorderTime(order.getPreorderTime());
        orderModel.setIsBonusPointsUsed(order.isBonusPointsUsed());
        orderModel.setBonusPointsUsed(order.getBonusPointsUsed());
        orderModel.setServiceShop(order.getServiceShop());
        orderModel.setNeedService(order.isNeedService());
        orderModel.setServiceFee(order.getTotalService());
        orderModel.setCouponOffer(order.getTotalOffer());
        orderModel.setShipmentFee(order.getTotalShippingFee());
        orderModel.setSubTotal(order.getSubTotal());
        orderModel.setTotal(order.getOrderTotal());
        List<OrderItem> items = order.getOrderItems();
        if (orderModel.getItems() == null) {
            orderModel.setItems(new ArrayList<ItemModel>());
        }
        items.forEach(item -> {
            ProductSku sku = productSkuService.getSkuById(item.getSkuId());
            ItemModel itemModel = new ItemModel();
            itemModel.setSkuId(item.getSkuId());
            itemModel.setSalePrice(item.getSkuPrice());
            itemModel.setRetailPrice(item.getRetailPrice());
            itemModel.setCategoryId(item.getCategoryId());
            itemModel.setNeedService(item.getHasService());
            //优惠券订单sku名称和图片改为优惠券信息
            if(OrderType.CASH_BY_COUPON.equalsIgnoreCase(order.getOrderType())){
                CouponDetail couponDetail = couponDetailRepository.findByCouponCode(item.getCouponCode());
                if(couponDetail != null){
                    itemModel.setSkuName(couponDetail.getCouponName() + "[" + couponDetail.getCouponCode() + "]");
                }
                Media media = couponRepository.findOne(order.getCouponId()).getMedia();
                itemModel.setImageUrl(media ==null?null: HttpRequestUtils.getUrl(media.getUrl()));
            }else {
                itemModel.setSkuName(item.getSkuName());
                itemModel.setImageUrl(productSkuService.getDefaultSkuMedia(sku));
            }
            itemModel.setSkuName(item.getSkuName());
            Integer returnQuantity = item.getReturnQuantity();
            Integer skuQuantity = item.getSkuQuantity();
            itemModel.setQuantity(skuQuantity);
            itemModel.setCanReturnQuantity(0);
            String status = order.getOrderStatus();
            if(OrderStatus.NEW.equalsIgnoreCase(status)||OrderStatus.CANCELED.equalsIgnoreCase(status)||
                    OrderStatus.PURCHASED.equalsIgnoreCase(status) ||OrderStatus.CONFIRMED.equalsIgnoreCase(status))
            {
                itemModel.setCanReturn(false);
            }else if(returnQuantity.compareTo(skuQuantity) >= 0){
                itemModel.setCanReturn(false);
            }else {
                itemModel.setCanReturn(true);
                itemModel.setCanReturnQuantity(skuQuantity - returnQuantity);
            }
            if (OrderItemStatus.RETURNING.equals(item.getStatus()) || OrderItemStatus.REFUNDED.equals(item.getStatus()))
                itemModel.setCanReturn(false);
            itemModel.setAppliedPromotionId(item.getAppliedPromoId());
            itemModel.setPromotionApplied(item.isPromoApplied());
            if (OrderStatus.NEW.equals(order.getOrderStatus())) {
                if(itemModel.isPromotionApplied()&& itemModel.getAppliedPromotionId()!=null){
                    itemModel.setAvailable(promotionService.isAvailable(itemModel.getAppliedPromotionId(),itemModel.getSkuId()));
                }else{
                    itemModel.setAvailable(productSkuService.isAvailable(productSkuService.getSkuById(item.getSkuId())));
                }
            }else
            {
                itemModel.setAvailable(Boolean.TRUE);
            }
            orderModel.getItems().add(itemModel);
            /*if (Boolean.TRUE.equals(item.getHasService())) {
                List<OrderItemService> services = item.getOrderItemServices();
                if (services != null) {
                    if (orderModel.getServices() == null) {
                        orderModel.setServices(new ArrayList<>());
                    }
                    services.forEach(service -> {

                        ProductService productService = service.getProductService();
                        ServiceModel serviceModel = new ServiceModel(productService.getServiceId(),
                                store == null ? null : store.getMerchantId(),
                                productService.getServiceName(),
                                productService.getServiceDescription(),
                                store == null ? null : store.getStoreName(), 1, service.getServicePrice());
                        orderModel.getServices().add(serviceModel);
                    });
                }
            }
            if (Boolean.TRUE.equals(item.hasGift())) {
                List<GiftwrapOrderItem> giftwrapOrderItems = item.getGiftwrapOrderItems();
                if (giftwrapOrderItems != null && !giftwrapOrderItems.isEmpty()) {
                    if (orderModel.getGifts() == null) {
                        orderModel.setGifts(new ArrayList<>());
                    }
                    giftwrapOrderItems.forEach(giftwrapOrderItem -> {
                        ItemModel giftItem = new ItemModel();
                        ProductSku giftSku = giftwrapOrderItem.getProductSku();
                        giftItem.setSkuId(giftSku.getSkuId());
                        giftItem.setSalePrice(giftSku.getSalePrice());
                        giftItem.setRetailPrice(giftSku.getRetailPrice());
                        giftItem.setCategoryId(giftSku.getCategory().getCategoryId());
                        giftItem.setNeedService(Boolean.FALSE);
                        giftItem.setSkuName(giftSku.getSkuName());
                        giftItem.setQuantity(giftwrapOrderItem.getQuantity());
                        giftItem.setImageUrl(productSkuService.getSkuDefaultMedia(giftSku).getUrl());
                        giftItem.setAvailable(productSkuService.isAvailable(giftSku));
                        orderModel.getGifts().add(giftItem);
                    });
                }
            }*/
        });
        return orderModel;
    }

    /**
     * 转换成前端可显示的订单基本信息
     *
     * @param order 订单
     * @return OrderModel
     */
    @Override
    public OrderBaseInfo convertToOrderBaseInfo(Order order) {
        OrderBaseInfo info = new OrderBaseInfo();
        MerchantStore store = order.getMerchantStore();
        info.setStoreId(store.getMerchantId());
        info.setStoreName(store.getStoreName());
        info.setStorePhone(store.getStorePhone());
        info.setAddr(getAddrDetail(order));
        info.setDate(order.getDatePurchased() == null ? "" : DateUtils.format(order.getDatePurchased(), DateUtils.DEFAULT_DATE_FORMAT));
        info.setDeliverNumber(order.getShippingModuleCode());
        info.setNeedInvoice(order.getNeedInvoice());
        info.setInvocieType(order.getInvoiceType());
        info.setInvoiceTitle(order.getInvoiceTitle());
        info.setTaxNumber(order.getTaxNumber());
        if (Boolean.TRUE.equals(order.isNeedService())) {
            info.setDeliverType("门店服务");
            info.setNeedService(true);
            MerchantStore serviceShop = storeService.getMerchantStore(order.getServiceShop());
            if (serviceShop != null) {
                info.setServiceShopName(serviceShop.getStoreName());
                info.setPreorderTime(order.getPreorderTime() == null ? "" : DateUtils.format(order.getPreorderTime(), DateUtils.DEFAULT_DATE_FORMAT));
            }
        } else {
            info.setDeliverType("快递");
        }
        info.setName(order.getDeliveryLastName());
        info.setNumber(order.getOrderNumber());
        info.setMessage(order.getCustomerMessage());
        info.setPhone(order.getDeliveryTelephonePrimary());
        Payment payment = order.getPayment();
        info.setPayType(payment == null ? "微信支付" : payment.getDescription());
        return info;
    }

    /**
     * 更加订单id查询订单
     *
     * @param id
     * @return 订单
     */
    @Override
    public Order findOrderById(Long id) {
        return orderRepository.findOne(id);
    }

    /**
     * 查询订单
     *
     * @param id       id
     * @param customer customer
     * @return 订单
     */
    @Override
    public Order findOrderByIdAndCustomer(Long id, Customer customer) {
        return orderRepository.findByOrderIdAndCustomer(id, customer);
    }

    protected Order persist(Order order) {
        /*Order existOrder = orderRepository.findByCustomerAndOrderNumber(order.getCustomer(),order.getOrderNumber());
        if(existOrder!=null){
            return existOrder;
        }*/
        return save(order);
    }

    /**
     * 获取不同订单状态数量
     *
     * @param customer
     * @return Map
     */
    @Override
    public Map countStatus(Customer customer, MerchantStore store) {
        Map map = new HashMap(16);
        map.put(OrderStatus.NEW, 0);
        map.put(OrderStatus.PURCHASED, 0);
        map.put(OrderStatus.PAID, 0);
        map.put(OrderStatus.CONFIRMED, 0);
        map.put(OrderStatus.SHIPPED, 0);
        map.put(OrderStatus.CANCELED, 0);
        map.put(OrderStatus.FINISHED, 0);
        List<Order> orders = orderRepository.findAllByCustomerAndMerchantStore(customer, store);
        if (CollectionUtils.isNotEmpty(orders)) {
            Map<String, List<Order>> maps = orders.stream().collect(Collectors.groupingBy(Order::getOrderStatus));
            for (String key : maps.keySet()) {
                map.put(key, maps.get(key).size());
            }
            long notHandledReturnsQuantity = orderReturnRepository.countNotHandledReturns(customer.getCustomerId(), store.getMerchantId());
            long notCommentQuantity = orderRepository.countNotCommentOrders(customer.getCustomerId(), store.getMerchantId(), CommentStatus.NOT_COMMENT);
            map.put("RETURN", notHandledReturnsQuantity);
            map.put("NOT_COMMENT", notCommentQuantity);
        }
        return map;
    }

    /**
     * 修改订单状态
     *
     * @param orderId orderId
     * @param status  status
     * @return 订单
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public Integer updateStatus(Long orderId, String status) {
        return updateStatus(orderId, status,null);
    }

    /**
     * 修改订单状态,发货状态
     *
     * @param orderId
     * @param status
     * @param shippingStatus
     * @return 订单
     */
    @Override
    public Integer updateStatus(Long orderId, String status, String shippingStatus) {
        return orderRepository.updateStatus(orderId, status,shippingStatus);
    }

    /**
     * 校验该门店是否提供指定的服务
     *
     * @param service
     * @param shop
     * @return
     */
    @Override
    public boolean serviceIsAvailable(com.bifrost.entity.ProductService service, MerchantStore shop) {
        List<ServicePrice> servicePrices = servicePriceRepository.findAllByProductServiceAndMerchantStore(service, shop);
        return servicePrices != null && servicePrices.size() > 0;

    }

    @Override
    public boolean canServiceForOrder(Order order) {
        if (Boolean.TRUE.equals(order.isNeedService())) {
            Long shopId = order.getServiceShop();
            MerchantStore store = storeService.getMerchantStore(shopId);
            List<OrderItem> items = order.getOrderItems();
            return items.stream().allMatch(item -> {
                Long sku = item.getSkuId();
                ProductSku productSku = productSkuService.getSkuById(sku);
                List<com.bifrost.entity.ProductService> services = productSkuService.getAssociationsOfService(productSku);
                return services.stream().allMatch(service -> {
                    return serviceIsAvailable(service, store);
                });
            });
        } else {
            return true;
        }
    }

    /**
     * 检查请求所有商品是否同个门店
     *
     * @param request
     * @return
     */
    @Override
    public MerchantStore allInOneStore(OrderRequest request) {
        Assert.notNull(request,"请求不能为空");
        List<ItemModel> items = request.getProducts();
        Assert.notNull(items,"商品信息不能为空");
        List<Long> skuIds = items.stream().map(ItemModel::getSkuId).collect(Collectors.toList());
        return allInOneStore(skuIds);
    }

    /**
     * 检查订单中所有商品是否同个门店
     *
     * @param order
     * @return
     */
    @Override
    public MerchantStore allInOneStore(Order order) {
        List<OrderItem> items = order.getOrderItems();
        List<Long> skuIds = items.stream().map(OrderItem::getSkuId).collect(Collectors.toList());
        return allInOneStore(skuIds);
    }

    /**
     * 为订单增加描述
     *
     * @param order
     * @return
     */
    @Override
    public void describeOrder(Order order) {
        List<OrderItem> items = order.getOrderItems();
        StringBuilder description = new StringBuilder();
        items.stream().forEach(orderItem -> {
            ProductSku sku = productSkuService.getSkuById(orderItem.getSkuId());
            description.append(sku.getSkuName());
            description.append("|").append(sku.getSalePrice());
            description.append("|").append(orderItem.getSkuQuantity());
        });
        order.setDescription(String.format("%s...", StringUtils.substring(description.toString(), 0, 50)));
    }

    /**
     * 更新订单外部交易号用于微信支付
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void updateOutTradeNo(Order order) {
        order.setOutTradeNo(String.format("%d", defaultUidGenerator.getUID()));
        orderRepository.save(order);
    }

    /**
     * 根据外部交易号查找订单
     *
     * @param outTradeNo
     * @return
     */
    @Override
    public Order findOrderByOutTradeNo(String outTradeNo) {
        return orderRepository.findFirstByOutTradeNo(outTradeNo);
    }

    protected MerchantStore allInOneStore(List<Long> skuIds) {

        if (skuIds != null && !skuIds.isEmpty()) {
            List<BigInteger> storeIds = productSkuRepository.findStoreIdsBySkuIds(skuIds);
            if (storeIds.size()==1) {
                return storeService.getMerchantStore(storeIds.get(0).longValue());
            }
        }
        return null;
    }

    /**
     * 取消订单
     * @param customer customer
     * @param orderId orderId
     * @param reason 原因
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void cancel(Customer customer, Long orderId,String reason) throws CancelOrderException {
        Order order = findOrderByIdAndCustomer(orderId, customer);
        if(order == null){
            throw new CancelOrderException("找不到对应的订单："+orderId);
        }
        RLock lock = redisson.getLock(String.format("%s.%d",Order.LOCK_KEY_PERFIX,order.getOrderId()));
        try {
            boolean locked = lock.tryLock(15,10, TimeUnit.SECONDS);
            if(locked){
                order = findOrderByIdAndCustomer(orderId, customer);
                if(OrderStatus.PURCHASED.equalsIgnoreCase(order.getOrderStatus())){
                    if(OrderType.CASH_BY_COUPON.equalsIgnoreCase(order.getOrderType())){
                        cancelUnpaidCouponOrder(order.getCustomer(),order.getOrderId(),reason);
                    }else {
                        cancelUnpaidOrder(order.getCustomer(), order.getOrderId(),reason);
                    }
                }
                else if(OrderStatus.PAID.equalsIgnoreCase(order.getOrderStatus())||OrderStatus.CONFIRMED.equalsIgnoreCase(order.getOrderStatus())){
                    //创建退款申请，并回滚订单相关
                    try {
                        rollback(order);
                    } catch (RollbackBonuspointsException | BonusPointsNotEnoughException e) {
                        throw new CancelOrderException(e.getMessage());
                    }
                    if (refundRequestService.buildRefundRequest(order)) {
                        order.setOrderStatus(OrderStatus.CANCELED);
                        save(order);
                        statusHistoryService.writeHistory(order,reason,Boolean.TRUE,null);
                    }else{
                        throw new CancelOrderException("创建退款申请失败");
                    }
                }else{
                    throw new CancelOrderException("创建退款申请失败");
                }
            }else{
                throw  new RuntimeException("获取订单锁失败");
            }
        } catch (InterruptedException e) {
           LOGGER.error(e.getMessage(),e);
            throw  new RuntimeException(e);
        } finally {
            if (lock.isLocked()) {
                lock.unlock();
            }
        }
    }

    @Override
    public List getStores(OrderRequest request) {
        List<MerchantStore> stores = storeService.getMerchantStores();
        if (stores != null) {
            stores.removeIf(merchantStore -> {
                List<Long> skus = request.getProducts().stream().map(ItemModel::getSkuId).collect(Collectors.toList());
                //所需服务
                List<com.bifrost.entity.ProductService> services = skus.stream().map(sku -> {
                    return skuAssociationRepository.findAllByproductSkuIdAndAssociationType(sku, AssociationType.SERVICE);
                }).filter(list -> {
                    return list != null;
                }).flatMap(List::stream).map(SkuAssociation::getProductService).collect(Collectors.toList());
                if (services == null || services.isEmpty()) {
                    return false;
                }
                //提供的服务
                List<com.bifrost.entity.ProductService> offerServices = merchantStore.getServicePrices().stream().filter(servicePrice -> {
                    return Boolean.TRUE.equals(servicePrice.getIsAvailable());
                }).map(ServicePrice::getProductService).collect(Collectors.toList());
                return !services.stream().allMatch(prodcutService -> {
                    boolean isTrue = offerServices.contains(prodcutService);
                    return isTrue;
                });
            });
        }
        if (stores != null && !stores.isEmpty()) {
            return stores.stream().sorted(Comparator.comparing(MerchantStore::getSortOrder)).collect(Collectors.toList());
        }
        return stores;
    }

    /**
     * 查询所有未支付订单
     *
     * @return
     */
    @Override
    public List<Order> findAllUnpaidOrders() {
        return orderRepository.findAllUnpaidOrders();
    }

    /**
     * 统计订单产生的积分
     *
     * @param order order
     * @return
     */
    @Override
    public Integer countBonusPoints(Order order) {
        return order.getOrderItems().stream().map(OrderItem::getBonusPoints).reduce(Integer::sum).get();
    }

    /**
     * 确认收货
     *
     * @param customer customer
     * @param orderId  orderId
     * @param code
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public ResultModel confirmReceived(Customer customer, Long orderId,@Nullable String code) {
        Order order = findOrderById(orderId);
        if (order == null || !OrderStatus.SHIPPED.equals(order.getOrderStatus())) {
            if(!order.getShippingType().equalsIgnoreCase("SELF_DELIVERY")||!OrderStatus.CONFIRMED.equalsIgnoreCase(order.getOrderStatus())){
                return ResultModel.error("失败");
            }
        }
        if (Boolean.TRUE.equals(order.isNeedService())) {
            return ResultModel.error("请到店接受服务后核销");
        }
        if(order.getShippingType().equalsIgnoreCase("SELF_DELIVERY")){
            Assert.isTrue(code!=null&&userService.findUserByCode(code.trim())!=null,"请检查提货码");
        }
        updateStatus(orderId, OrderStatus.FINISHED,ShippmentStatus.RECEIVED);
        statusHistoryService.writeHistory(order, "已确认收货", Boolean.TRUE,code);
        return ResultModel.ok("成功");
    }

    @Override
    public List<Order> hasRefundVaildOrder(Order order) {
        if (order != null)
        {
            return orderRepository.findVaildRefundOrders(order.getOrderNumber());
        }
        return null;
    }

    /**
     * 返回详细收货地址
     *
     * @param order order
     * @return
     */
    @Override
    public String getAddrDetail(Order order) {
        CountryArea state = order.getDeliveryState();
        CountryArea city = order.getDeliveryCity();
        CountryArea distinct = order.getDeliveryDistrict();
        if (state == null || city == null || distinct == null) {
            return null;
        }
        StringBuilder addr = new StringBuilder();
        addr.append(state.getName());
        addr.append(city.getName());
        addr.append(distinct.getName());
        addr.append(order.getDeliveryStreet());
        return addr.toString();
    }

    /**
     * 获取订单详情
     *
     * @param order
     * @return
     */
    @Override
    public Map orderDetails(Order order) {
        OrderModel model = convertToOrderModel(order);
        OrderBaseInfo info = convertToOrderBaseInfo(order);
        String orderStatus = "";
        //是否可以付款
        boolean canPay = false;
        //是否可以申请取消订单
        boolean canCancel = false;
        //是否可以申请退款(发货前)，
        boolean canRefund = false;
        //是否可以确认收货
        boolean canConfirm = false;
        //是否可以查看物流
        boolean canViewShippmentHistory = false;
        //是否可以评论
        boolean canComment = false;
        //是否可以申请售后服务（退货）
        boolean canReturn = false;
        //是否显示核销二维码
        boolean showQRCode = false;
        Map result = new HashMap();

        //待发货
        if (OrderStatus.PURCHASED.equalsIgnoreCase(order.getOrderStatus())) {
            canPay = true;
            canCancel = true;
        }
        //已支付
        else if (OrderStatus.PAID.equalsIgnoreCase(order.getOrderStatus())) {
            canRefund = true;
            canCancel = true;
        }
        //已确认
        else if (OrderStatus.CONFIRMED.equalsIgnoreCase(order.getOrderStatus())) {
            canRefund = true;
            canCancel = true;
            if(ShippingType.SELF_DELIVERY.equalsIgnoreCase(order.getShippingType())) canConfirm = true;
        }
        //已发货
        else if (OrderStatus.SHIPPED.equalsIgnoreCase(order.getOrderStatus())) {
            canConfirm = true;
            canViewShippmentHistory = true;
            canReturn = true;
            if(ShippingType.SELF_DELIVERY.equalsIgnoreCase(order.getShippingType()))
                showQRCode = true;
        }
        //已收货
        else if (OrderStatus.FINISHED.equalsIgnoreCase(order.getOrderStatus())) {
            canReturn = true;
            canViewShippmentHistory = true;
            if (CommentStatus.NOT_COMMENT.equals(order.getCommentStatus()))
                canComment = true;
            /*List<OrderReturn> orderReturnList = orderReturnRepository.findVaildRefundOrders(order.getOrderId());
            if (CollectionUtils.isEmpty(orderReturnList))
                canReturn = true;*/
        }

        if(OrderType.EXCHANGE.equalsIgnoreCase(order.getOrderType())){
            canPay = false;
            canCancel = false;
            canRefund = false;
            canReturn = false;
        }

        /*if (CollectionUtils.isNotEmpty(orderReturnRepository.findVaildRefundOrders(order.getOrderId()))) {
            canReturn = false;
        }*/

        result.put("status", order.getOrderStatus());
        result.put("orderStatus", getStatusDesc(order));
        result.put("orderId", order.getOrderId());
        result.put("info", info);
        result.put("canPay", canPay);
        result.put("canRefund", canRefund);
        result.put("canCancel", canCancel);
        result.put("canReturn", canReturn);
        result.put("canConfirm", canConfirm);
        result.put("canComment", canComment);
        result.put("showQRCode", showQRCode);
        result.put("canViewShippmentHistory", canViewShippmentHistory);
        result.put("order", model);
        return result;
    }

    @Override
    public OrderResult orderOverview(Order order) {
        OrderResult orderResult = new OrderResult();
        orderResult.setOrderId(order.getOrderId());
        String orderType = order.getOrderType();
        orderResult.setOrderType(orderType);
        List<OrderItem> items = order.getOrderItems();
        if (CollectionUtils.isNotEmpty(items)) {
            OrderItem itemFirst = items.get(0);
            ProductSku sku = productSkuService.getSkuById(itemFirst.getSkuId());
            //优惠券订单sku名称改为优惠券信息
            if(OrderType.CASH_BY_COUPON.equalsIgnoreCase(orderType)){
                CouponDetail couponDetail = couponDetailRepository.findByCouponCode(itemFirst.getCouponCode());
                if(couponDetail != null){
                    orderResult.setSkuName(couponDetail.getCouponName() + "[" + couponDetail.getCouponCode() + "]");
                    Media media = couponRepository.findOne(order.getCouponId()).getMedia();
                    orderResult.setUrl(media ==null?null: HttpRequestUtils.getUrl(media.getUrl()));
                }
            }else {
                orderResult.setSkuName(itemFirst.getSkuName());
                orderResult.setUrl(productSkuService.getDefaultSkuMedia(sku));
            }
            orderResult.setTotleFee(order.getOrderTotal());
            orderResult.setOrderNumber(order.getOrderNumber());
            orderResult.setStatus(order.getOrderStatus());
            orderResult.setShippingType(order.getShippingType());
            if(OrderType.EXCHANGE.equalsIgnoreCase(orderType)){
                orderResult.setBonusPointsUsed(order.getBonusPointsUsed());
            }
            orderResult.setOrderStatus(getStatusDesc(order));
            Long quantity = orderRepository.countOrderItem(order.getOrderId());
            orderResult.setQuantity(quantity == null ? 1L : quantity);
            return orderResult;
        }
        return null;
    }

    private Date calculatePreorderDate(List<Integer> days) {
        LocalDate today = LocalDate.now();
        Integer maxDays = days.stream().max((integer1, integer2) -> {
            return integer1.compareTo(integer2);
        }).get();
        LocalDate preOrderDate = today.plus(maxDays, ChronoUnit.DAYS);
        return LocalDateUtils.fromLocalDate(preOrderDate);

    }

    /**
     * 获取订单状态描述
     *
     * @param order
     * @return
     */
    @Override
    public String getStatusDesc(Order order) {
        String desc = "";
        //待发货
        if (OrderStatus.PURCHASED.equalsIgnoreCase(order.getOrderStatus())) {
            desc = "待付款";
        }
        //已支付
        else if (OrderStatus.PAID.equalsIgnoreCase(order.getOrderStatus())) {
            desc = "已支付";
        }
        //已确认
        else if (OrderStatus.CONFIRMED.equalsIgnoreCase(order.getOrderStatus())) {
            desc = "待发货";
        }
        //已发货
        else if (OrderStatus.SHIPPED.equalsIgnoreCase(order.getOrderStatus())) {
            if (Boolean.TRUE.equals(order.isNeedService())) {
                desc = "待服务";
            } else {
                desc = "待收货";
            }
        }
        //已收货
        else if (OrderStatus.FINISHED.equalsIgnoreCase(order.getOrderStatus())) {
            if (!Boolean.TRUE.equals(order.isNeedService())) {
                desc = "已收货";
            } else {
                desc = "已核销";
            }
        }
        //取消
        else if (OrderStatus.CANCELED.equalsIgnoreCase(order.getOrderStatus())) {
            desc = "已取消";
        } else {
            desc = "已完成";
        }

        return desc;
    }

    /**
     * 获取不同状态所有订单
     *
     * @param status
     * @return
     */
    @Override
    public List<Order> findAllByStatus(String status) {
        if (StringUtils.isNotEmpty(status)) {
            return orderRepository.findAllByOrderStatus(status);
        }
        return null;
    }

    /**
     * 15天自动收货
     */
    @Override
    public void autoConfirmReceive() {
        List<Order> orderList = findAllByStatus(OrderStatus.SHIPPED);
        if (CollectionUtils.isNotEmpty(orderList)) {
            orderList.forEach(order -> {
                Date shipDate = orderStatusHistoryService.getTime(order.getOrderId(), OrderStatus.SHIPPED);
                LocalDate receiveDate = LocalDateUtils.fromDate(shipDate).plusDays(15L);
                if (receiveDate.isBefore(LocalDate.now())) {
                    confirmReceived(order.getCustomer(), order.getOrderId(),null);
                }
            });
        }
    }

    /**
     * 获取所有未评价订单
     *
     * @return
     */
    @Override
    public List<Order> findAllNotCommentOrder() {
        return orderRepository.findAllByCommentStatusAndOrderStatus(CommentStatus.NOT_COMMENT, OrderStatus.FINISHED);
    }
    /**
     * 确认订单信息
     *
     * @param order
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public int confirmOrder(Order order) throws ConfirmCanceledOrderException {
        Assert.notNull(order,"订单不能为空");
        RLock lock = redisson.getLock(String.format("%s.%d",Order.LOCK_KEY_PERFIX,order.getOrderId()));
        try {
           boolean locked = lock.tryLock(15,10,TimeUnit.SECONDS);
           if(locked){
               int updated =orderRepository.confirmOrder(order.getOrderId());
               if(updated!=1){
                   Order order1 = findOrderById(order.getOrderId());
                   if(OrderStatus.CANCELED.equals(order1.getOrderStatus()))
                   {
                       throw new ConfirmCanceledOrderException();
                   }
                   throw  new RuntimeException("确认订单失败："+order1.getOrderId());
               } else{
                   order.setOrderStatus(OrderStatus.CONFIRMED);
                   return 1;
               }
           }else{
               throw  new RuntimeException("获取订单锁失败");
           }
        } catch (InterruptedException e) {
            LOGGER.error(e.getMessage(),e);
            throw  new RuntimeException(e);
        } finally {
            if (lock.isLocked()) {
                lock.unlock();
            }
        }
    }
    /**
     * 取消未支付订单
     * @param customer
     * @param orderId
     * @param reason
     * @return
     */
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public void cancelUnpaidOrder(Customer customer, Long orderId, String reason) throws CancelOrderException {
        Order order = findOrderByIdAndCustomer(orderId, customer);
        if(order == null){
           throw new CancelOrderException("找不到对应的订单:"+orderId);
        }
        RLock lock = redisson.getLock(String.format("%s.%d",Order.LOCK_KEY_PERFIX,order.getOrderId()));
        try {
           boolean locked =  lock.tryLock(15,10,TimeUnit.SECONDS);
           if(locked){
               rollback(order);
               if(!OrderStatus.CANCELED.equalsIgnoreCase(order.getOrderStatus())){
                   order.setOrderStatus(OrderStatus.CANCELED);
                   cancelUnpaidOrder(order);
                   //记录日志
                   statusHistoryService.writeHistory(order,reason,Boolean.TRUE,null);
               }
           }else {
               throw new CancelOrderException("获取订单锁失败");
           }
        } catch (RollbackBonuspointsException e) {
            //未付款订单没有积分所以理论上是不会执行到此处的，
            LOGGER.error(e.getMessage());
            throw new CancelOrderException("取消订单失败:"+e.getMessage());
        } catch (InterruptedException e) {
            throw new CancelOrderException("取消订单失败:"+e.getMessage());
        } catch (BonusPointsNotEnoughException e) {
            throw new CancelOrderException("取消订单失败:"+e.getErrorMsg());
        } finally {
            if (lock.isLocked()) {
                lock.unlock();
            }
        }
    }
    /**
     * 构建积分消息
     *
     * @param orderId
     * @param loyaltyNo
     * @return
     */
    @Override
    @Transactional
    public Map buildBonusponitsMsgMapByOrder(Long orderId, String loyaltyNo) {
        Assert.notNull(loyaltyNo,"会员卡号不能为空");
        Order order = findOrderById(orderId);
        MerchantStore store = order.getMerchantStore();
        Map msg =new HashMap<String,Object>();
        List goodsList =new ArrayList<>();
        List payInfoist = new ArrayList<>();
        String storeId = store.getExternalId();
        if (StringUtils.isBlank(storeId)) {
            throw new RuntimeException("门店外部系统id为空");
        }
        //收银机号X001
        msg.put("vsyjh","X001");
        //小票流水号
        msg.put("vfphm",order.getOrderNumber());
        //交易时间
        msg.put("vrqsj", DateUtils.format(order.getDatePurchased(),DateUtils.DEFAULT_DATE_FORMAT));
        //会员卡号
        msg.put("vhykh",loyaltyNo);
        //应收金额单位元
        msg.put("vysje",order.getOrderTotal().toString());
        //小票类别 (销售  1   退货 4)
        msg.put("vdjlb","1");
        //经营公司门店号
        msg.put("mktcode",storeId);
        msg.put("salecom",goodsList);
        msg.put("salepay",payInfoist);
        List<OrderItem> items = order.getOrderItems();
        for(OrderItem orderItem :items) {
            String code = orderItem.getExternalId();
            if (StringUtils.isBlank(code)) {
                throw new RuntimeException("sku外部系统id为空");
            }
            Long productId = orderItem.getProductId();
            Product product = productService.findProduct(productId);
            if(product==null){
               ProductSku sku = productSkuService.getSkuById(orderItem.getSkuId());
               product = sku.getProduct();
            }
            if(product!=null){
                Map item = new HashMap();
                //条码
                item.put("vbarcode",code);
                //sap编码
                item.put("vcode",code);
                //类别
                item.put("vdzxl",product.getExternalCcategory());
                //品牌
                item.put("vpp",product.getProductBrand().getProductBrandId());
                //数量
                item.put("vsl",orderItem.getSkuQuantity());
                //零售价
                item.put("vlsj",orderItem.getRetailPrice());
                //实际价格
                item.put("vjg",orderItem.getSkuPrice());
                //小计
                item.put("vzje",orderItem.getSkuPrice().multiply(BigDecimal.valueOf(orderItem.getSkuQuantity())));
                goodsList.add(item);
            }
        }
        Map payInfo = new HashMap();
        //微信支付
        payInfo.put("vpaycode","5001");
        //金额
        payInfo.put("vybje",order.getOrderTotal());
        //付款号
        payInfo.put("vpayno",order.getOutTradeNo());
        payInfo.put("vidno",order.getCustomer().getOpenId());
        payInfo.put("vflag","1");
        payInfoist.add(payInfo);
        return msg;

    }

    /**
     * 取消未支付订单
     * @param order
     * @return
     */
    private void cancelUnpaidOrder(Order order) throws CancelOrderException {
        Assert.notNull(order,"订单不能为空");
        int update = orderRepository.cancelOrder(order.getOrderId());
        if(update !=1){
            order =  orderRepository.findOne(order.getOrderId());
            throw  new CancelOrderException("订单不能取消,状态："+order.getOrderStatus());
        }
    }

    /**
     * 订单相关回滚操作
     *
     * @param orederId
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void rollbackByOrder(Long orederId) throws RollbackBonuspointsException, BonusPointsNotEnoughException {
        Assert.notNull(orederId,"订单id不能为空");
        rollback(findOrderById(orederId));
    }

    /**
     * 回滚订单相关项
     * @param order
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void rollback(Order order) throws RollbackBonuspointsException, BonusPointsNotEnoughException {
        Assert.notNull(order,"订单不能为空");
        if(OrderStatus.CANCELED.equals(order.getOrderStatus())){
            return;
        }
        RLock lock = redisson.getLock(String.format("%s.%d",Order.LOCK_KEY_PERFIX,order.getOrderId()));
        try {
            boolean locked =  lock.tryLock(15,10,TimeUnit.SECONDS);
            if(locked){
                //回滚库存
                Map<ProductSku, Integer> map = inventoryService.buildSkuInventoryMap(order);
                Map<String, Object> context = new HashMap<>();
                context.put(InventoryService.ORDER_TYPE,order.getOrderType());
                context.put(InventoryService.ORDER_KEY,order);
                inventoryService.incrementInventory(map,context);
                //退还订单奖励的积分
                OrderAttribute loyalty = orderAttributeRepository.findFirstByAttributeNameAndOrder(OrderAttribute.LOYALTY_NUMBER,order);
                if(loyalty != null){
                    customerService.rollbackBounsPoints(order,loyalty.getAttributeValue());
                    //退还CRM系统赠送积分
                    if(!OrderStatus.PURCHASED.equalsIgnoreCase(order.getOrderStatus())&&!OrderStatus.NEW.equalsIgnoreCase(order.getOrderStatus())){
                        OrderAttribute attribute = orderAttributeRepository.findFirstByAttributeNameAndOrder(OrderAttribute.CRM_STATUS,order);
                        //已积分成功
                        if(attribute!=null&&OrderAttribute.SUCCESS.equalsIgnoreCase(attribute.getAttributeValue())){
                            Map msg= buildBonusponitsMsgMapByOrder(order.getOrderId(),order.getCustomer().getLoyaltyCard());
                            /**
                             * 小票流水号
                             * */
                            msg.put("vfphm",determineTransNumber(order.getMerchantStore().getExternalId(),TransactionSendLog.Type.CANCEL,order.getOrderId()));
                            /**
                             * 退货
                             * */
                            msg.put("vdjlb","4");
                            JSONObject result = memberService.sendSales(msg);
                            if (!"0".equals(result.getString("errCode"))) {
                                attribute.setAttributeValue(OrderAttribute.ROLLBACK_FAILURE);
                                orderAttributeRepository.save(attribute);
                                LOGGER.error(String.format("取消订单%d积分失败:%s",order.getOrderId(),result.getString("errMessage")));
                                throw new RollbackBonuspointsException(String.format("取消订单%d积分失败:%s",order.getOrderId(),result.getString("errMessage")));
                            }else{
                                attribute.setAttributeValue(OrderAttribute.ROLLBACK_ALL);
                                orderAttributeRepository.save(attribute);
                                LOGGER.info(String.format("取消订单%d积分成功",order.getOrderId()));
                            }
                        }
                    }
                }
                //退优惠券
                List<OrderCoupon> couponList =order.getOrderCoupons();
                if(couponList!=null&&!couponList.isEmpty()){
                    Set<CouponDetail> couponDetails = couponList.stream().map(OrderCoupon::getCouponDetail).collect(Collectors.toSet());
                    couponDetails.forEach(couponDetail->{
                        couponService.rollbackCouponDetailIsUnused(couponDetail);
                    });
                }
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            if (lock.isLocked()) {
                lock.unlock();
            }
        }
    }

    /**
     * 售后单相关回滚操作
     *
     * @param orederReturnId
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void rollbackByOrderReturn(Long orederReturnId) throws RollbackBonuspointsException, BonusPointsNotEnoughException {
        Assert.notNull(orederReturnId,"售后单id不能为空");
        rollback(orderReturnRepository.findOne(orederReturnId));
    }

    /**
     * 售后单相关回滚操作
     *
     * @param orederReturn
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void rollback(OrderReturn orederReturn) throws RollbackBonuspointsException, BonusPointsNotEnoughException {
        Assert.notNull(orederReturn, "售后单不能为空");
        Order order = orederReturn.getRelatedOrder();
        if (order == null) {
            throw new RuntimeException(String.format("售后单%d原订单不存在：", orederReturn.getId()));
        }
        if (RollbackStatus.ROLLBACKED.equals(orederReturn.getRollbackStatus())) {
            return;
        }

        List<OrderReturnItem> items = orederReturn.getOrderReturnItems();
        //Map returnItemsMap= new HashMap(items.size());
        if (CollectionUtils.isEmpty(items)) {
            throw new RuntimeException(String.format("售后单%d的有效行项目为0", orederReturn.getId()));
        }
        List<Map> list = new ArrayList<>();
        items.forEach(orderReturnItem -> {
            Long skuId = orderReturnItem.getSkuId();
            String code = orderReturnItem.getExternalId();
            //returnItemsMap.put(code,orderReturnItem);
            ProductSku sku = productSkuService.getSkuById(skuId);
            Map<String, Object> context = new HashMap<>(2);
            Product product = sku.getProduct();
            /**
             * 构建退货结构
             * */
            Map item = new HashMap(8);
            //条码
            item.put("vbarcode", code);
            //sap编码
            item.put("vcode", code);
            //类别
            item.put("vdzxl", product.getExternalCcategory());
            //品牌
            item.put("vpp", product.getProductBrand().getProductBrandId());
            //数量
            item.put("vsl", orderReturnItem.getSkuQuantity());
            //零售价
            item.put("vlsj", orderReturnItem.getRetailPrice());
            //实际价格
            item.put("vjg", orderReturnItem.getSkuPrice());
            //小计
            item.put("vzje", orderReturnItem.getSkuPrice().multiply(BigDecimal.valueOf(orderReturnItem.getSkuQuantity())));
            list.add(item);

            //FIXME  促销订单库存回滚
                //TODO 促销订单的退货
                //context.put(InventoryService.ORDER_TYPE,order.getOrderType());
                //context.put(InventoryService.ORDER_KEY,order);
                inventoryService.incrementInventory(sku, orderReturnItem.getSkuQuantity(), context);
        });
        orederReturn.setRollbackStatus(RollbackStatus.ROLLBACKED);
        orderReturnRepository.save(orederReturn);
        OrderAttribute loyalty = orderAttributeRepository.findFirstByAttributeNameAndOrder(OrderAttribute.LOYALTY_NUMBER,order);
        if(loyalty != null) {
            //退还订单奖励的积分
            customerService.rollbackBounsPoints(orederReturn,loyalty.getAttributeValue());
            //退crm积分
            OrderAttribute attribute = orderAttributeRepository.findFirstByAttributeNameAndOrder(OrderAttribute.CRM_STATUS,order);
            if(attribute!=null){
                if(OrderAttribute.SUCCESS.equalsIgnoreCase(attribute.getAttributeValue())
                        ||OrderAttribute.ROLLBACK_PARTIAL.equalsIgnoreCase(attribute.getAttributeValue())
                        ||OrderAttribute.ROLLBACK_FAILURE.equalsIgnoreCase(attribute.getAttributeValue()))
                {
                    Map msg = buildBonusponitsMsgMapByOrder(order.getOrderId(), order.getCustomer().getLoyaltyCard());
                    //小票流水号
                    msg.put("vfphm",determineTransNumber(order.getMerchantStore().getExternalId(),TransactionSendLog.Type.REFUND,orederReturn.getId()));
                    //退货
                    msg.put("vdjlb","4");
                    msg.put("vysje",orederReturn.getRefundTotal());
                    msg.put("salecom",list);
                    JSONObject result = memberService.sendSales(msg);
                    if (!"0".equals(result.getString("errCode"))) {
                        LOGGER.error(String.format("取消订单%d积分失败:%s",order.getOrderId(),result.getString("errMessage")));
                        attribute.setAttributeValue(OrderAttribute.ROLLBACK_FAILURE);
                        orderAttributeRepository.save(attribute);
                        throw new RollbackBonuspointsException(String.format("取消订单%d积分失败:%s",order.getOrderId(),result.getString("errMessage")));
                    }else{
                        LOGGER.info(String.format("取消订单%d积分成功",order.getOrderId()));
                        attribute.setAttributeValue(OrderAttribute.ROLLBACK_ALL);
                        orderAttributeRepository.save(attribute);
                    }
                }
            }
        }
        //退优惠券
        List<OrderCoupon> couponList =order.getOrderCoupons();
        if(couponList!=null&&!couponList.isEmpty()){
            Set<CouponDetail> couponDetails = couponList.stream().map(OrderCoupon::getCouponDetail).collect(Collectors.toSet());
            couponDetails.forEach(couponDetail->{
                couponService.rollbackCouponDetailIsUnused(couponDetail);
            });
        }
    }

    /**
     * 生成交易小票号，不保证唯一
     * @param storeCode
     * @param type
     * @param id
     * @return
     */
    @Override
    public String determineTransNumber(String storeCode, TransactionSendLog.Type type, Long id) {
        Assert.notNull(storeCode, "门店编号不能为null");
        Assert.notNull(type, "交易类型不能为空");
        Assert.notNull(id, "订单id不能为空");
        if(runningMode.equalsIgnoreCase(RunningMode.PRODUCTION)){
            if (TransactionSendLog.Type.SALES.equals(type)) {
                return String.format("%s0%08d", storeCode, id);
            }
            else if (TransactionSendLog.Type.CANCEL.equals(type)) {
                return String.format("%s1%08d", storeCode, id);
            }else if (TransactionSendLog.Type.REFUND.equals(type)) {
                return String.format("%s2%08d", storeCode, id);
            } else {
                throw new UnsupportedOperationException(type.toString());
            }
        }else{
            if (TransactionSendLog.Type.SALES.equals(type)) {
                return String.format("0%s0%08d", storeCode, id);
            }
            else if (TransactionSendLog.Type.CANCEL.equals(type)) {
                return String.format("0%s1%08d", storeCode, id);
            }else if (TransactionSendLog.Type.REFUND.equals(type)) {
                return String.format("0%s2%08d", storeCode, id);
            } else {
                throw new UnsupportedOperationException(type.toString());
            }
        }

    }

    /**
     * 创建优惠券订单
     * @param coupon
     * @param quantity
     * @param customer
     * @param payType
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Order newCouponOrder(Coupon coupon, Integer quantity, Customer customer, String payType){
        //校验用户是否可以购买此优惠券
        if(!checkCanBuy(customer,coupon,quantity)){
            throw new CouponBuyException("该优惠券暂不可购买");
        }
        //创建订单
        Order order = new Order();
        order.setCustomer(customer);
        order.setCouponId(coupon.getCouponId());
        order.setShippingType(ShippingType.SELF_DELIVERY);
        order.setMerchantStore(customer.getMerchantStore());
        describeCouponOrder(order,quantity);
        /*
         * 设置支付方式为微信支付
         */
        order.setPayment(paymentService.getPayment(1l));
        order.setOrderItems(new ArrayList<>());
        save(order);
        String orderNum = NumberUtils.determineOrderNumber(order);
        order.setOutTradeNo(orderNum);
        order.setOrderNumber(orderNum);
        /*
        创建优惠券订单项
         */
        //优惠券替代商品
        ProductSku productSku = productSkuRepository.findFirstByExternalId("1001");
        Product product = productSku.getProduct();
        for(int i = 0; i < quantity ; i++) {
            OrderItem item = new OrderItem();
            item.setOrder(order);
            item.setSkuId(productSku.getSkuId());
            item.setSkuName(coupon.getCouponName());
            item.setSkuQuantity(1);
            item.setSkuCost(productSku.getSkuCost());
            item.setSkuUPC(productSku.getSkuUpc());
            item.setExternalId(productSku.getExternalId());
            item.setRetailPrice(coupon.getPrice());
            item.setSkuPrice(coupon.getPrice());
            item.setOrderItemType(OrderItemType.BASIC);
            item.setCategoryId(product.getProductCategory().getCategoryId());
            item.setProductId(product.getProductId());
            Long uuid = defaultUidGenerator.getUID();
            item.setCouponCode(uuid);
            orderItemRepository.save(item);
            order.getOrderItems().add(item);
        }
        order.setOrderType(OrderType.CASH_BY_COUPON);
        order.setOrderTotal(coupon.getPrice().multiply(BigDecimal.valueOf(quantity)));
        return order;

    }

    /**
     * 描述优惠券信息
     * @param order
     * @param quantity
     */
    private void describeCouponOrder(Order order, Integer quantity) {
        List<OrderItem> items = order.getOrderItems();
        Coupon coupon = couponRepository.findOne(order.getCouponId());
        StringBuilder description = new StringBuilder();
        description.append(coupon.getCouponName());
        description.append("|").append(coupon.getPrice());
        //description.append("|").append(quantity);
        order.setDescription(String.format("%s...", StringUtils.substring(description.toString(), 0, 50)));
    }

    /**
     * 处理优惠券订单，生成优惠券明细
     * @param order
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleCouponOrder(Order order) {
        if(CollectionUtils.isEmpty(order.getOrderItems())){
            return;
        }

        //是优惠券订单
        if(OrderType.CASH_BY_COUPON.equalsIgnoreCase(order.getOrderType())){
            Coupon coupon = couponRepository.findOne(order.getCouponId());
            Assert.notNull(coupon,"优惠券id有误");
            /*
            List<CouponDetail> notSells = couponDetailRepository.findAllByCouponAndCustomerIsNull(coupon.getCouponId());
            int notSellAmount = 0;
            int index = 0;
            if(CollectionUtils.isNotEmpty(notSells)){
                notSellAmount = notSells.size();
            }
            */
            for(OrderItem orderItem : order.getOrderItems()){
                //先使用已生成但未使用的优惠券
                /*
                if(notSellAmount != 0){
                    CouponDetail couponDetail = notSells.get(index);
                    //更新优惠券码生成时间以作为优惠券的售出时间
                    couponDetail.setGeneratedTime(new Date());
                    couponDetail.setCustomer(order.getCustomer());
                    orderItem.setCouponCode(couponDetail.getCouponCode());
                    index ++;
                    notSellAmount --;
                    continue;
                }
                */
                Long couponCode = orderItem.getCouponCode();
                Assert.notNull(couponCode,"优惠券码不能为空");
                if(couponDetailRepository.findByCouponCode(couponCode) != null){
                    continue;
                }
                CouponDetail couponDetail =new CouponDetail();
                couponDetail.setIsUsed(Boolean.FALSE);
                BeanUtils.copyProperties(coupon,couponDetail);
                couponDetail.setCoupon(coupon);
                couponDetail.setCustomer(order.getCustomer());
                couponDetail.setGeneratedTime(new Date());
                couponDetail.setCouponCode(couponCode);
                couponDetailRepository.save(couponDetail);
                /*
                 * 有效期为领取之日起
                 * */
                if(ValidityType.DAYS.equalsIgnoreCase(couponDetail.getValidityType())){
                    couponDetail.setActiveStartDate(LocalDateUtils.fromLocalDateTime(LocalDateTime.now()));
                    couponDetail.setActiveEndDate(LocalDateUtils.fromLocalDateTime(LocalDateTime.now().plus(coupon.getValidityDays(),ChronoUnit.DAYS)));
                }
                //设置优惠券订单项关联的优惠券码
                orderItem.setCouponCode(couponDetail.getCouponCode());
                //保存优惠券购买记录
                Long transactionId = defaultUidGenerator.getUID();
                CouponHistroy histroy = new CouponHistroy(transactionId,
                        couponDetail.getCouponDetailId(),
                        order.getCustomer().getCustomerId(),
                        order.getOrderNumber(),
                        CouponHistroy.Operation.NEW,
                        String.format("购买优惠券：核销码%s,订单：%s",couponCode,order.getOrderNumber()));
                couponHistroyRepository.save(histroy);
            }
            //order.setOrderStatus(OrderStatus.FINISHED);
            //save(order);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void finishOrder(Order order) {
        Assert.notNull(order,"订单不能为空");
        RLock lock = redisson.getLock(String.format("%s.%d",Order.LOCK_KEY_PERFIX,order.getOrderId()));
        try {
            boolean locked = lock.tryLock(15,10,TimeUnit.SECONDS);
            if(locked){
                int updated =orderRepository.finishOrder(order.getOrderId());
                if(updated!=1){
                    throw  new RuntimeException("完成订单失败："+order.getOrderId());
                }
            }else{
                throw  new RuntimeException("获取订单锁失败");
            }
        } catch (InterruptedException e) {
            LOGGER.error(e.getMessage(),e);
            throw  new RuntimeException(e);
        } finally {
            if (lock.isLocked()) {
                lock.unlock();
            }
        }
    }

    @Override
    public void cancelUnpaidCouponOrder(Customer customer, Long orderId, String reason) throws CancelOrderException {
        Order order = findOrderByIdAndCustomer(orderId, customer);
        if(order == null){
            throw new CancelOrderException("找不到对应的订单:"+orderId);
        }
        RLock lock = redisson.getLock(String.format("%s.%d",Order.LOCK_KEY_PERFIX,order.getOrderId()));
        try {
            boolean locked =  lock.tryLock(15,10,TimeUnit.SECONDS);
            if(locked){
                //扣减优惠券数量
                try {
                    couponRepository.incrementCouponQuantityAvailable(order.getCouponId(), 1);
                }catch (Exception e){
                    throw new CouponBuyException("优惠券数量不足，请重新尝试");
                }
                if(!OrderStatus.CANCELED.equalsIgnoreCase(order.getOrderStatus())){
                    cancelUnpaidOrder(order);
                    //记录日志
                    statusHistoryService.writeHistory(order,reason,Boolean.TRUE,null);
                }
            }else {
                throw new CancelOrderException("获取订单锁失败");
            }
        }  catch (InterruptedException e) {
            throw new CancelOrderException("取消订单失败:"+e.getMessage());
        } finally {
            if (lock.isLocked()) {
                lock.unlock();
            }
        }
    }

    /**
     * 校验用户是否能够购买此优惠券
     * @param customer
     * @param coupon
     * @param quantity
     * @return
     */
    private boolean checkCanBuy(Customer customer, Coupon coupon, Integer quantity) {
        if (coupon==null||Boolean.FALSE.equals(coupon.getIsEnabled()) || CouponAuthStatus.SOLD_OUT.equalsIgnoreCase(coupon.getAuthStatus())) {
            throw new CouponBuyException("优惠券已下架");
        } else if(coupon!=null&&couponService.isBetweenReleasePeriod(coupon)){
            //已购买
            Integer count = couponDetailRepository.countByCustomerAndCoupon(customer, coupon);
            //未支付
            Integer noPaidCouponOrderCount = orderRepository.countByCustomerAndCouponIdAndOrderStatus(customer,coupon.getCouponId(),OrderStatus.PURCHASED);
            /**
             * 用户领取次数小于优惠券单用户领取次数限制
             * **/
            if(coupon.getMaxUsesPerCustomer().compareTo(count+noPaidCouponOrderCount)>0){
                //可用数量大于0
                if(coupon.getQuantityAvailable()>0){
                    //扣减优惠券数量
                    if(couponRepository.decrementCouponQuantityAvailable(coupon.getCouponId(),quantity)==1){
                        return true;
                    }else {
                        throw new CouponBuyException("优惠券数量不足，请重新尝试");
                    }
                }else {
                    throw new CouponBuyException("优惠券数量不足，请重新尝试");
                }
            }else {
                throw new CouponBuyException("优惠券单人购买数量超过上限");
            }
        }
        return false;
    }

}
